package org.budo.support.spring.aop.util;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.budo.support.slf4j.Slf4j;
import org.budo.support.spring.context.aware.BudoApplicationContextAware;
import org.budo.support.spring.util.SpringUtil;
import org.slf4j.Logger;
import org.springframework.aop.support.AopUtils;
import org.springframework.context.ApplicationContext;

/**
 * @author lmw
 * @see org.springframework.aop.framework.AopContext#currentProxy()
 */
public class AopUtil {
    private static final Logger log = Slf4j.getLogger();

    private static final Map<Object, Object> AOP_PROXY_CACHE_MAP = new ConcurrentHashMap<Object, Object>();

    /**
     * 传入一个对象，返回与之对应的经过Aop包装的对象
     */
    public static <T> T proxy(T target) {
        if (null == target) {
            return null;
        }

        Object proxy = AOP_PROXY_CACHE_MAP.get(target); // 缓存
        if (null != proxy) {
            return (T) proxy;
        }

        if (AopUtils.isAopProxy(target)) {
            AOP_PROXY_CACHE_MAP.put(target, target); // 自己
            return target;
        }

        BudoApplicationContextAware applicationContextAware = BudoApplicationContextAware.getInstance();
        if (null == applicationContextAware) {
            log.warn("#42 no applicationContextAware, return it-self : " + target);
            return target; //
        }

        ApplicationContext applicationContext = applicationContextAware.getApplicationContext();
        Class<?> targetType = target.getClass();

        T proxyedBean = (T) SpringUtil.getBean(applicationContext, targetType);
        if (null == proxyedBean) {
            log.warn("#45 not found bean for targetType " + targetType + ", return it-self : " + target);
            return target; //
        }

        AOP_PROXY_CACHE_MAP.put(target, proxyedBean); // Bean
        return proxyedBean;
    }
}